/**
 * ProcessOrder.java
 *
 * Enterprise Java
 *
 * Author:  Matthew Braddy
 * Created: Oct 18, 2010
 *
 */

package java113.project.base;

import java113.project.xml.WriteXMLOutput;
import java113.project.xml.ReadXMLOrder;
import java113.project.threads.Scanner;
import java113.project.threads.ThreadedWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import java113.project.util.DocVsSecurityException;
import java.io.*;
import java.util.*;

/**
 *
 * @author Matthew Braddy
 */
public class ProcessOrder {
    
    private Properties properties;

    private Map        orders;

    private Logger     logger;

    private Charges    charges;

    /**
     *
     * @param properties
     */
    public ProcessOrder(Properties properties) throws DocVsSecurityException {

        setProperties(properties);

        logger = Logger.getLogger(properties.getProperty("logger"));

        orders = new Hashtable();

        readCharges();

    }
    
    /**
     *
     * @return
     */
    public Properties getProperties() {

        return this.properties;

    }

    /**
     *
     * @param properties
     */
    public void setProperties(Properties properties) {

        this.properties = properties;

    }

    /**
     *
     * @param orderMap
     */
    public void setOrders(Map orderMap) {

        this.orders = orderMap;

    }

    /**
     *
     * @return
     */
    public Map getOrders() {

        return this.orders;

    }

    /**
     *
     * @param inputFilePath
     * @return
     * @throws DocVsSecurityException
     */
    public List readOrder(String inputFilePath) throws DocVsSecurityException {
        
        List orderInfo = new ArrayList();
        
        BufferedReader br = null;

        try {

            if ( ( inputFilePath == null ) || ( inputFilePath.length() == 0 ) ) {

                throw new DocVsSecurityException( "Path cannot be empty", DocVsSecurityException.INPUT_FAIL, "inputFilePath", inputFilePath );

            } else if ( inputFilePath.length() > 512 ) {

                throw new DocVsSecurityException("Path cannot exceed 512 characters", DocVsSecurityException.INPUT_FAIL, "inputFilePath", inputFilePath );

            } else if ( inputFilePath.indexOf( ' ' ) >= 0 ) {

                throw new DocVsSecurityException( "Path cannot contain spaces", DocVsSecurityException.INPUT_FAIL, "inputFilePath", inputFilePath );
                
            }

            if (properties.getProperty("webApp").equalsIgnoreCase("false")) {

                br = new BufferedReader( new FileReader( inputFilePath ) );

            } else {

                InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(inputFilePath);

                br = new BufferedReader( new InputStreamReader( stream ) );

            }
            
            logger.log(Level.INFO, inputFilePath +
                    " has been opened for reading.");

            while ( br.ready() ) {

                orderInfo.add( br.readLine() );

                logger.log(Level.INFO, "A line has been read in from " +
                        inputFilePath +
                        ".");
                
            }

            if ((orderInfo == null) || (orderInfo.size() == 0)) {
                throw new DocVsSecurityException("File contents cannot be empty", DocVsSecurityException.OUTPUT_FAIL, "strIn", orderInfo);
            } else if (orderInfo.size() > 1000000000) {
                throw new DocVsSecurityException("File should not exceed 1Gb in size", DocVsSecurityException.OUTPUT_FAIL, "strIn.length()", orderInfo.size());
            }


        } catch (FileNotFoundException fne) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + fne.getMessage());

            fne.printStackTrace();

        } catch (IOException ioe) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + ioe.getMessage());

            ioe.printStackTrace();

        } catch (Exception e) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + e.getMessage());

            e.printStackTrace();

        } finally {

            try {

                br.close();

            } catch (Exception e) {

                logger.log(Level.SEVERE,
                    "Encountered an exception: " + e.getMessage());

                e.printStackTrace();

            }

        }

        return orderInfo;

    }

    /**
     *
     * @param d
     * @throws DocVsSecurityException
     */
    public void readCharges() throws DocVsSecurityException {

        this.charges = new Charges();

        int[]    itemRange  = new int[4];
        double[] itemCharge = new double[4];
        String[] sarray     = new String[2];
        int      counter    = 0;

        BufferedReader br = null;

        try {

            String inputFilePath = properties.getProperty("path.input") +
                                   properties.getProperty("file.charges");

            if ( ( inputFilePath == null ) ||
                    ( inputFilePath.length() == 0 ) ) {
                throw new DocVsSecurityException( "Path cannot be empty",
                                               DocVsSecurityException.INPUT_FAIL,
                                               "inputFilePath", 
                                               inputFilePath );
            } else if ( inputFilePath.length() > 512 ) {
                throw new DocVsSecurityException(
                                            "Path cannot exceed 512 characters",
                                            DocVsSecurityException.INPUT_FAIL,
                                            "inputFilePath",
                                            inputFilePath );
            } else if ( inputFilePath.indexOf( ' ' ) >= 0 ) {
                throw new DocVsSecurityException( "Path cannot contain spaces",
                                               DocVsSecurityException.INPUT_FAIL,
                                               "inputFilePath", 
                                               inputFilePath );
            }

            if (properties.getProperty("webApp").equalsIgnoreCase("false")) {

                br = new BufferedReader( new FileReader( inputFilePath ) );

            } else {

                InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(inputFilePath);

                br = new BufferedReader( new InputStreamReader( stream ) );

            }

            logger.log(Level.INFO, inputFilePath +
                    " has been opened for reading.");

            while ( br.ready() ) {
                String s = br.readLine();

                sarray              = s.split( " " );
                itemRange[counter]  = Integer.parseInt( sarray[0] );
                itemCharge[counter] = Double.parseDouble( sarray[1] );

                counter++;

                logger.log(Level.INFO, "A line has been read in from " +
                        inputFilePath +
                        ".");

            }

        } catch (FileNotFoundException fne) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + fne.getMessage());

            fne.printStackTrace();

        } catch (IOException ioe) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + ioe.getMessage());

            ioe.printStackTrace();

        } catch (Exception e) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + e.getMessage());

            e.printStackTrace();

        } finally {

            try {

                br.close();

            } catch (Exception e) {

                logger.log(Level.SEVERE,
                    "Encountered an exception: " + e.getMessage());

                e.printStackTrace();

            }

        }

        charges.setItemCharge(itemCharge);
        charges.setItemRange(itemRange);
    }

    public void assignCharges( Order d ) throws DocVsSecurityException {

        d.setHChargeQuantity( charges.getItemRange() );
        d.setHChargeAmount( charges.getItemCharge() );
        
    }

    /**
     *
     * @param orderInfo
     * @return
     * @throws DocVsSecurityException
     */
    public Map createOrder(List orderInfo) throws DocVsSecurityException {
        
        if ((orderInfo == null) || (orderInfo.size() == 0)) {
            throw new DocVsSecurityException(
                    "File contents cannot be empty", 
                    DocVsSecurityException.OUTPUT_FAIL, "strIn", orderInfo);
            
        } else if (orderInfo.size() > 1000000000) {
            throw new DocVsSecurityException(
                    "File should not exceed 1Gb in size", 
                    DocVsSecurityException.OUTPUT_FAIL, 
                    "strIn.length()", orderInfo.size());
            
        }

        
        
        for (int i = 0; i < orderInfo.size(); i++) {

            Order    d      = new Order();

            String[] sorder = ( ( String ) orderInfo.get( i ) ).split( "\\s" );


            d.setCustomerName( sorder[0] );

            d.setCustomerNumber( Integer.parseInt( sorder[1] ) );

            d.setQuantity( Integer.parseInt( sorder[2] ) );

            d.setUnitPrice( Double.parseDouble( sorder[3] ) );

            d.setItem( sorder[4] );

            assignCharges( d );

            orders.put( ( int ) i, d );

            try {

                Thread.sleep(1000);

            } catch (InterruptedException ex) {

                Logger.getLogger(ProcessOrder.class.getName()).log(Level.SEVERE, null, ex);

            }

        }

        return orders;

    }

    /**
     *
     * @param outputFilePath
     * @param orders
     * @throws DocVsSecurityException
     */
    public void writeOutput(String outputFilePath, Map orders) throws DocVsSecurityException {

        PrintWriter pr = null;
        
        try {

            Iterator i = orders.entrySet().iterator();
            
            StringBuffer printingStager = null;
            
            pr = new PrintWriter(outputFilePath);

            logger.log(Level.INFO, outputFilePath + " has been created.");

            // Begin output path checks
            if ((outputFilePath == null) || (outputFilePath.length() == 0)) {
                throw new DocVsSecurityException("Path cannot be empty", DocVsSecurityException.INPUT_FAIL, "outputFilePath", outputFilePath);
            } else if (outputFilePath.length() > 512) {
                throw new DocVsSecurityException("Path cannot exceed 512 characters", DocVsSecurityException.INPUT_FAIL, "outputFilePath", outputFilePath);
            } else if (outputFilePath.indexOf(' ') >= 0) {
                throw new DocVsSecurityException("Path cannot contain spaces", DocVsSecurityException.INPUT_FAIL, "outputFilePath", outputFilePath);
            }

            printingStager = new StringBuffer();
            
            while (i.hasNext()) {

                Map.Entry me = (Map.Entry) i.next();
                
                Order d = (Order) me.getValue();

                printingStager.append(d.toString());
                //printingStager.append(System.getProperty ("line.separator"));
                logger.log(Level.INFO, "A line has been written to the output file.");

            }

            // Begin output content checks
            if ((printingStager == null) || (printingStager.length() == 0)) {
                throw new DocVsSecurityException("File contents cannot be empty", DocVsSecurityException.OUTPUT_FAIL, "strIn", printingStager);
            } else if (printingStager.length() > 1000000000) {
                throw new DocVsSecurityException("File should not exceed 1Gb in size", DocVsSecurityException.OUTPUT_FAIL, "strIn.length()", printingStager.length());
            }

            pr.println(printingStager.toString());

        } catch (FileNotFoundException fne) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + fne.getMessage());

            fne.printStackTrace();

        } catch (IOException ioe) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + ioe.getMessage());

            ioe.printStackTrace();

        } catch (Exception e) {

            logger.log(Level.SEVERE,
                    "Encountered an exception: " + e.getMessage());

            e.printStackTrace();

        } finally {

            try {

                pr.close();

            } catch (Exception e) {

                logger.log(Level.SEVERE,
                    "Encountered an exception: " + e.getMessage());

                e.printStackTrace();

            }

        }
        
    }

    /**
     *
     * @throws DocVsSecurityException
     */
    public void run() throws DocVsSecurityException, Exception {
        
        if (properties.getProperty("multithread").equals("true")) {

            logger.log(Level.INFO, "\nApplication started in multi-threaded " +
                    "mode.");
            
            Scanner        scanner        = new Scanner(orders, this.properties);
            ThreadedWriter threadedWriter = new ThreadedWriter(orders, this.properties);

            Thread scannerThread  = new Thread(scanner);
            Thread writerThread   = new Thread(threadedWriter);

            scannerThread.start();
            logger.log(Level.INFO, "Starting the scanner thread.");
            
            writerThread.start();
            logger.log(Level.INFO, "Starting the writer thread.");
            
            String input = properties.getProperty("path.input") +
                           properties.getProperty("flat.file.input");

            createOrder(readOrder(input));
            
        } else {

            logger.log(Level.INFO, "\nApplication started in single" +
                    "threaded mode.");

            if (properties.getProperty("xml").equals("true")) {

                logger.log(Level.INFO, "Application using xml.");

                ReadXMLOrder readXMLOrder = new ReadXMLOrder(this.properties);

                readXMLOrder.load();

                WriteXMLOutput writeXML = new WriteXMLOutput(this.properties, readXMLOrder.getOrders());

                writeXML.write();

            } else {

                logger.log(Level.INFO, "Application using flatfile.");

                String input = properties.getProperty("path.input") +
                               properties.getProperty("flat.file.input");

                String output = properties.getProperty("path.output") +
                                properties.getProperty("flat.file.output");

                writeOutput(output, createOrder(readOrder(input)));

            }

            
            
        }
        
        
        
    }

    /**
     *
     * @return
     */
    @Override
    public String toString() {

        StringBuffer strbHold;

        strbHold = new StringBuffer();
        strbHold.append("Properties file: " + this.properties.toString());
        strbHold.append(System.getProperty("line.separator"));
        strbHold.append("Orders: " + this.orders.toString());
        return strbHold.toString ();

    }

}

